package com.ayq.activiti.manager.controller;

import com.ayq.activiti.common.util.DataResult;
import com.ayq.activiti.common.util.PageParams;
import com.ayq.activiti.common.util.Ret;
import com.ayq.activiti.manager.service.CustomDeploymentService;
import com.ayq.activiti.manager.service.CustomModelService;
import com.ayq.activiti.manager.service.CustomTaskService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.repository.Model;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 * <p>流程模型控制类</p>
 *
 * @Author ayq
 * @Date 2021/3/8 14:41
 */
@Controller
@RequestMapping("/models")
@Api(tags = "流程模型中心")
@Slf4j
public class ActivitiModelController {

    private static final Logger LOGGER = LoggerFactory.getLogger(ActivitiModelController.class);

    @Autowired
    private CustomModelService customModelService;
    @Autowired
    private CustomDeploymentService customDeploymentService;
    @Autowired
    private CustomTaskService customTaskService;

    /**
     * <p>跳转模型列表页面</p>
     * <p>方法名:getListHtml</p>
     *
     * @Author ayq
     * @Date 2021/3/10 14:57
     * @Param []
     * @Return java.lang.String
     */
    @RequestMapping(value = "/index", method = RequestMethod.GET)
    public String getListHtml() {
        return "model/list";
    }

    /**
     * <p>模型列表</p>
     * <p>方法名:modelList</p>
     *
     * @Author ayq
     * @Date 2021/3/8 14:41
     * @Param [model, request]
     * @Return java.lang.String
     */
    @ApiOperation(value = "获取模型列表", notes = "获取模型列表")
    @GetMapping(value = "/modelList")
    @ResponseBody
    public Ret modelList(PageParams pageParams) {
        customModelService.modelList(pageParams);
        return Ret.ok(pageParams);
    }

    /*
     * <p>创建空模型</p>
     * <p>方法名:newModel</p>
     * @Author ayq
     * @Date 2021/3/8 17:31
     * @Param [request, response]
     * @Return void
     */
    @ApiOperation(value = "创建空模型", notes = "创建空模型")
    @GetMapping("/create")
    @ResponseBody
    public DataResult newModel(HttpServletRequest request, HttpServletResponse response) {
        try {
            return DataResult.success(customModelService.newModel(request, response));
        } catch (Exception e) {
            LOGGER.error("模型创建失败！", e);
            return DataResult.fail(e.getMessage());
        }
    }

    /**
     * <p>打包方式部署流程模型</p>
     * <p>方法名:deployModle</p>
     *
     * @Author ayq
     * @Date 2021/3/11 10:25
     * @Param [file]
     * @Return org.ezca.esign.common.base.Ret
     */
    @ApiOperation(value = "打包方式部署流程模型", notes = "打包方式部署流程模型")
    @PostMapping("/fileModel")
    @ResponseBody
    public Ret deployModle(@RequestParam("fileModel") MultipartFile file) {
        ZipInputStream zipInputStream = null;
        byte[] bytes = null;
        byte[] bpmnBytes = null;
        try {
            return customModelService.deployModle(file, zipInputStream, bytes, bpmnBytes);
        } catch (Exception e) {
            LOGGER.error("定制化模型上传失败！", e);
            return Ret.error("上传失败");
        } finally {
            if (zipInputStream != null) {
                try {
                    zipInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * <p>删除流程模型</p>
     * <p>方法名:deleteModel</p>
     *
     * @Author ayq
     * @Date 2021/3/8 14:45
     * @Param [id]
     * @Return java.lang.String
     */
    @ApiOperation(value = "删除流程模型", notes = "删除流程模型")
    @PostMapping("/delete/model/{id}")
    public @ResponseBody
    DataResult deleteModel(@PathVariable("id") String id) {
        if (customModelService.deleteModel(id)) {
            return DataResult.getResult(DataResult.success().getCode(),"删除流程模型成功");
        } else {
            return DataResult.fail("流程已部署！无法删除,请先删除已部署的流程");
        }
    }

    /**
     * <p>删除部署流程实例</p>
     * <p>方法名:deleteDeployment</p>
     *
     * @Author ayq
     * @Date 2021/3/12 11:17
     * @Param [id]
     * @Return org.ezca.esign.common.base.Ret
     */
    @ApiOperation(value = "删除部署流程实例", notes = "删除部署流程实例")
    @PostMapping("/delete/deployment/{id}")
    public @ResponseBody
    Ret deleteDeployment(@PathVariable("id") String id) {
        if ("".equals(id) || id == null) {
            return Ret.error("删除主键不合法！无法删除");
        } else {
            try {
                customDeploymentService.deleteDeployment(id);
            } catch (Exception e) {
                LOGGER.error("有流程正在运行！无法删除，请等待流程结束", e);
                return Ret.error("有流程正在运行！无法删除，请等待流程结束");
            }
        }
        return Ret.ok("删除成功", null);
    }

    /**
     * <p>强制删除部署流程（不建议使用：会删除跟流程有关的信息及历史信息）</p>
     * <p>方法名:deleteRmDeployment</p>
     *
     * @Author ayq
     * @Date 2021/3/12 11:18
     * @Param [id]
     * @Return org.ezca.esign.common.base.Ret
     */
    @ApiOperation(value = "强制删除部署流程（不建议使用：会删除跟流程有关的信息及历史信息）", notes = "强制删除部署流程（不建议使用：会删除跟流程有关的信息及历史信息）")
    @PostMapping("/delete/rmDeployment/{id}")
    public @ResponseBody
    Ret deleteRmDeployment(@PathVariable("id") String id) {
        if ("".equals(id) || id == null) {
            return Ret.error("删除主键不合法！无法删除");
        } else {
            try {
                customDeploymentService.deleteRmDeployment(id);
            } catch (Exception e) {
                LOGGER.error("强制删除部署流程失败", e);
                return Ret.error("强制删除部署流程失败");
            }
        }
        return Ret.ok("删除成功", null);
    }


    /**
     * <p>获取流程列表</p>
     * <p>方法名:deploymentList</p>
     *
     * @Author ayq
     * @Date 2021/3/12 13:31
     * @Param [pageParams]
     * @Return org.ezca.esign.common.base.Ret
     */
    @ApiOperation(value = "获取流程列表", notes = "获取流程列表")
    @GetMapping(value = "/deploymentList")
    @ResponseBody
    public Ret deploymentList(PageParams pageParams) {
        customDeploymentService.deploymentList(pageParams);
        return Ret.ok(pageParams);
    }

    /**
     *
     * <p>获取所有流程列表</p>
     * <p>方法名:deploymentAllList</p>
     * @Author ayq
     * @Date 2021/3/30 17:52
     * @Param []
     * @Return org.ezca.esign.common.base.Ret
     */
    @ApiOperation(value = "获取所有流程列表", notes = "获取所有流程列表")
    @GetMapping(value = "/deploymentAllList")
    @ResponseBody
    public Ret deploymentAllList() {
        return Ret.ok(customDeploymentService.deploymentAllList());
    }

    /**
     *
     * <p>根据流程key获取流程版本</p>
     * <p>方法名:getVersionByKey</p>
     * @Author ayq
     * @Date 2021/3/31 11:49
     * @Param [pKey]
     * @Return org.ezca.esign.common.base.Ret
     */
    @ApiOperation(value = "根据流程key获取流程版本", notes = "根据流程key获取流程版本")
    @GetMapping(value = "/getVersionByKey")
    @ResponseBody
    public Ret getVersionByKey(String key){
        return Ret.ok(customDeploymentService.getVersionByKey(key));
    }


    /**
     * <p>部署流程实例</p>
     * <p>方法名:deploy</p>
     *
     * @Author ayq
     * @Date 2021/3/8 14:53
     * @Param [id]
     * @Return java.lang.String
     */
    @ApiOperation(value = "部署流程实例", notes = "部署流程实例")
    @PostMapping("/deployment/{id}")
    public @ResponseBody
    DataResult deploy(@PathVariable("id") String id) {
        ZipOutputStream zos = null;
        ZipInputStream zis = null;
        try {
            customDeploymentService.deploy(id, zos, zis);
            return DataResult.success("流程发布成功");
        } catch (Exception e) {
            LOGGER.error("流程发布失败", e);
            return DataResult.fail("流程发布失败");
        } finally {
            if (zos != null) {
                try {
                    zos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (zis != null) {
                try {
                    zis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * <p>根据模型ID查看模型流程</p>
     * <p>方法名:findModel</p>
     *
     * @Author ayq
     * @Date 2021/3/8 16:13
     * @Param [request, response]
     * @Return void
     */
    @ApiOperation(value = "根据模型ID查看模型流程", notes = "根据模型ID查看模型流程")
    @GetMapping("/find/{modelId}")
    public void findModel(@PathVariable("modelId") String modelId, HttpServletResponse response) throws Exception {
        response.sendRedirect("/static/modeler.html?modelId=" + modelId);
    }

    /**
     * <p>根据部署流程ID查看模型流程</p>
     * <p>方法名:findModelToDid</p>
     *
     * @Author ayq
     * @Date 2021/3/12 14:39
     * @Param [deploymentId, response]
     * @Return void
     */
    @ApiOperation(value = "根据部署流程ID查看模型流程", notes = "根据部署流程ID查看模型流程")
    @GetMapping("/findToDid/{deploymentId}")
    public void findModelToDid(@PathVariable("deploymentId") String deploymentId, HttpServletResponse response) throws Exception {
        Model model = customDeploymentService.findModelToDid(deploymentId);
        response.sendRedirect("/static/modeler.html?modelId=" + model.getId());
    }

    /**
     * <p>根据任务ID查看流程图</p>
     * <p>方法名:getDeploymentIdBpmnImgs</p>
     *
     * @Author ayq
     * @Date 2021/3/25 11:24
     * @Param [deploymentId, resourceName, resp]
     * @Return void
     */
    @ApiOperation(value = "根据部署ID查看流程图", notes = "根据部署ID查看流程图")
    @GetMapping("/getDeploymentIdBpmnImgs/{deploymentId}")
    public void getDeploymentIdBpmnImgs(@PathVariable("deploymentId") String deploymentId, String resourceName, HttpServletResponse resp) {
        try {
            customDeploymentService.getDeploymentIdBpmnImgs(deploymentId, resourceName, resp);
        } catch (Exception e) {
            LOGGER.error("deploymentId:" + deploymentId + "生成流程图失败", e);
        }
    }


    /**
     * <p>流程图跟踪</p>
     * <p>方法名:getBpmnImgs</p>
     *
     * @Author ayq
     * @Date 2021/3/17 13:41
     * @Param [taskId]
     * @Return java.io.InputStream
     */
    @ApiOperation(value = "根据任务ID查看流程图", notes = "根据任务ID查看流程图")
    @GetMapping("/getBpmnImgs/{taskId}")
    @ResponseBody
    public void getBpmnImgs(@PathVariable("taskId") String taskId, HttpServletResponse response) {
        InputStream imageStream = null;
        String processInstanceId = null;
        try {
            if (StringUtils.isEmpty(taskId)) {
                LOGGER.error("任务Id为空");
                return;
            }
            customTaskService.getBpmnImgs(taskId, response, imageStream, processInstanceId);
        } catch (Exception e) {
            LOGGER.error("processInstanceId" + processInstanceId + "生成流程图失败，", e);
        } finally {
            if (imageStream != null) {
                try {
                    imageStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * <p>根据部署ID查看流程信息</p>
     * <p>方法名:getDeploymentIdBpmnXml</p>
     *
     * @Author ayq
     * @Date 2021/3/25 17:55
     * @Param [deploymentId, resourceName, model]
     * @Return java.lang.String
     */
    @ApiOperation(value = "根据部署ID查看流程信息", notes = "根据部署ID查看流程信息")
    @RequestMapping(value = "/getDeploymentIdBpmnXml/{deploymentId}", method = RequestMethod.GET)
    @ResponseBody
    public DataResult getDeploymentIdBpmnXml(@PathVariable("deploymentId") String deploymentId, String resourceName, org.springframework.ui.Model model) {
        try {
            return DataResult.success(customDeploymentService.getDeploymentIdBpmnXml(deploymentId, resourceName));
        } catch (Exception e) {
            LOGGER.error("deploymentId:" + deploymentId + "生成流程信息失败", e);
            return DataResult.fail(e.getMessage());
        }
    }

    /**
     * <p>设置流程状态</p>
     * <p>方法名:setSuspended</p>
     *
     * @Author ayq
     * @Date 2021/3/25 17:58
     * @Param [key, isSuspended]
     * @Return org.ezca.esign.common.base.Ret
     */
    @ApiOperation(value = "设置流程状态", notes = "设置流程状态")
    @PostMapping(value = "/setSuspended")
    @ResponseBody
    public Ret setSuspended(String key, boolean isSuspended) {
        return Ret.ok(customDeploymentService.setSuspended(key, isSuspended));
    }

    @RequestMapping(value = "/activitiVersion", method = RequestMethod.GET)
    public String getActivitiVersionHtml(String key, org.springframework.ui.Model model) {
        model.addAttribute("key", key);
        return "model/activitiVersion";
    }

    /**
     * <p>获取流程所有版本</p>
     * <p>方法名:deploymentAllListVersion</p>
     *
     * @Author ayq
     * @Date 2021/3/26 15:57
     * @Param [pageParams, key]
     * @Return org.ezca.esign.common.base.Ret
     */
    @ApiOperation(value = "获取流程所有版本", notes = "获取流程所有版本")
    @GetMapping(value = "/deploymentAllListVersion/{key}")
    @ResponseBody
    public Ret deploymentAllListVersion(PageParams pageParams, @PathVariable("key") String key) {
        customDeploymentService.deploymentAllListVersion(pageParams, key);
        return Ret.ok(pageParams);
    }

    /**
     *
     * <p>模型文件下载</p>
     * <p>方法名:exportActivitiZip</p>
     * @Author ayq
     * @Date 2021/3/26 17:34
     * @Param [resourceName, res]
     * @Return void
     */
    @ApiOperation(value = "模型文件下载", notes = "模型文件下载")
    @PostMapping(value = "/exportActivitiZip")
    public void exportActivitiZip(String resourceName,HttpServletResponse res) throws Exception {
        BufferedInputStream bis = null;
        OutputStream os = null;
        try {
            customDeploymentService.exportActivitiZip(resourceName,res,bis,os);
        } catch (Exception e) {
            LOGGER.error("流程文件下载失败", e);
            throw new Exception(e.getMessage());
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
